package com.redball;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

class Panel extends SurfaceView implements SurfaceHolder.Callback
{
	public final double GRAVITY_FACTOR = 3;

	// Magic numbers
	// private final int POSITION_TESTING_FACTOR = 10;
	public final double SLOW_MOTION_FACTOR = 0.5;
	private final int COMPASS_FACTOR = 50;

	// Gravity members
	public float yVector = 1;
	public float xVector = 0;
	public float _gravityX = 0;
	public float _gravityY = 0;

	// Members
	private LifeCycleThread _thread;
	private final int NUM_OF_BALLS = 1;
	// private GraphicObject _redBall;
	private ArrayList<GraphicObject> _graphicObjects;
	// private boolean _isTouched = false;
	// private double _deltaX = 0;
	// private double _deltaY = 0;
	// private int _oldX = 0;
	// private int _oldY = 0;
	// private int _savePosition = 0;
	private boolean _isPaused = false;
	// private boolean _onChangeGravity = false;
	private Boolean isStartUp = true;

	private Paint _p = new Paint();

	// private GravitySelector _gravitySelector;
	// Canvas properties
	private int canvasHeight = 800;
	private int canvasWidth = 400;

	// Walls
	Wall wall = new Wall();

	public Panel(Context context)
	{
		super(context);
		getHolder().addCallback(this);
		setFocusable(true);
		_graphicObjects = new ArrayList<GraphicObject>();
		for (int i = 0; i < NUM_OF_BALLS; ++i)
		{
			_graphicObjects.add(new RedBall(this,
					BitmapFactory.decodeResource(getResources(), R.drawable.redball), getWidth() * 4,
					600 - (i * 50)));
		}
		// _gravitySelector = new GravitySelector();
	}

	public void updatePhysics()
	{
		if (_isPaused)
		{
			return;
		}

		for (GraphicObject obj : _graphicObjects)
		{
			obj.updatePhysics();

			GraphicObject.Coordinates coord = obj.getCoordinates();

			// Checking if it touches the shape
			Line tmpLine = wall.checkIfHit(coord.getX(), coord.getY(), obj.getGraphic().getWidth() / 2);
			if (tmpLine != null)
			{
				obj.handleColission(wall.getNormal(tmpLine));
			}
			for (GraphicObject obj2 : _graphicObjects)
			{
				if (obj == obj2)
				{
					continue;
				}
				if (Math.abs(obj2.getCoordinates().getX() - obj.getCoordinates().getX()) < (obj.getGraphic()
						.getWidth() + obj2.getGraphic().getWidth())
						&& Math.abs(obj2.getCoordinates().getY() - obj.getCoordinates().getY()) < (obj
								.getGraphic().getHeight() + obj2.getGraphic().getHeight()))
				{
					obj.handleObjectColission(obj.getCoordinates());
				}
			}

		}
	}

	public void setGravityX(float gravityX)
	{
		this._gravityX = gravityX;
	}

	public void setGravityY(float gravityY)
	{
		this._gravityY = gravityY;
	}

	public void togglePause(boolean toStop)
	{
		if (toStop != _isPaused)
		{
			togglePause();
		}
	}

	public boolean togglePause()
	{
		_isPaused = !_isPaused;
		return _isPaused;
	}

	public boolean isPaused()
	{
		return _isPaused;
	}

	// public void changeGravity()
	// {
	// togglePause(false);
	// xVector = (getWidth() / 2) + (xVector * (getWidth() / 5));
	// yVector = (getHeight() / 2) + (xVector * (getHeight() / 5));
	// // _onChangeGravity = true;
	// }

	@Override
	public void onDraw(Canvas canvas)
	{
		if (canvas == null)
		{
			return;
		}
		
		if(isStartUp) startUp(canvas);

		// Background color
		canvas.drawColor(Color.WHITE);

		_p.setStrokeWidth(4);

		// if (_onChangeGravity){
		// _gravitySelector.draw(canvas);
		// }

		drawCompass(canvas);

		for (GraphicObject obj : _graphicObjects)
		{
			obj.draw(canvas);
		}
		_p.setColor(Color.GREEN);
		// Drawing the wall
		wall.draw(canvas, _p);
		// }

	}

	// Dose some initial settings for the game.
	private void startUp(Canvas canvas)
	{
		if(canvas != null) {
			canvasHeight = canvas.getHeight();
			canvasWidth = canvas.getWidth();
		}
		wall.setWall(canvasHeight / 10, canvasWidth / 10, 
				canvasHeight * 3 / 10, canvasWidth * 2 / 10,
				canvasHeight * 3 / 10, canvasWidth * 35 / 100, 
				canvasHeight * 1 / 10, canvasWidth * 4 / 10);
		
		isStartUp = false;
	}

	/**
	 * Draws the compass
	 * 
	 * @param c
	 *            - canvas
	 */
	private void drawCompass(Canvas c)
	{
		double x = Math.cos(getGravityAngle());
		double y = Math.sin(getGravityAngle());

		int compassCenterX = c.getWidth() * 4 / 5;
		int compassCenterY = c.getHeight() * 1 / 5;
		int compassEndX = (int) (compassCenterX + x * COMPASS_FACTOR * getGravityPower());
		int compassEndY = (int) (compassCenterY + y * COMPASS_FACTOR * getGravityPower());
		int radius = 10;

		_p.setColor(Color.BLACK);
		c.drawCircle(compassCenterX, compassCenterY, radius + COMPASS_FACTOR + 10, _p);
		_p.setColor(Color.WHITE);
		c.drawCircle(compassCenterX, compassCenterY, radius + COMPASS_FACTOR + 8, _p);

		_p.setColor(Color.BLACK);
		c.drawLine(compassCenterX, compassCenterY, compassEndX, compassEndY, _p);
		_p.setColor(Color.RED);
		c.drawCircle(compassEndX, compassEndY, radius, _p);
	}

	public double getGravityPower()
	{
		return Math.sqrt(Math.pow(_gravityY / 7, 2) + Math.pow(_gravityX / 7, 2));
	}

	public double getGravityAngle()
	{
		double _degree =(_gravityX != 0) ? Math.atan(FloatMath.ceil(_gravityY * 50) / FloatMath.ceil(_gravityX * 50)) : 0;
		// System.out.println("ELI_X: "+ _gravityX);
		// System.out.println("ELI_Y: "+ _gravityY);
		// System.out.println("ELI_D: "+ Math.toDegrees(_degree));

		if (_gravityX < 0)
		{
			if (_degree < 0)
			{
				_degree += (Math.PI);
			} else
			{
				_degree -= (Math.PI);
			}
		}
		// System.out.println("_gravityY:" + _gravityY);
		// System.out.println("_gravityX:" + _gravityX);
		double angleFactor = getGravityPower();
		xVector = (float) (Math.cos(_degree) * GRAVITY_FACTOR * SLOW_MOTION_FACTOR * angleFactor);
		yVector = (float) (Math.sin(_degree) * GRAVITY_FACTOR * SLOW_MOTION_FACTOR * angleFactor);
		return _degree;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		synchronized (_thread.getSurfaceHolder())
		{
			for (GraphicObject obj : _graphicObjects)
			{
				obj.onTouchEvent(event);
			}
			// if (_onChangeGravity) {
			// _gravitySelector.onTouchEvent(event);
			// }
			// if (event.getAction() == MotionEvent.ACTION_DOWN)
			// {
			// int TOUCH_FACTOR = 20;
			// if (event.getX() > _redBall.getCoordinates().getX() -
			// TOUCH_FACTOR
			// && event.getX() < _redBall.getCoordinates().getX() +
			// _redBall.getGraphic().getWidth() + TOUCH_FACTOR
			// && event.getY() > _redBall.getCoordinates().getY() - TOUCH_FACTOR
			// && event.getY() < _redBall.getCoordinates().getY() +
			// _redBall.getGraphic().getHeight() + TOUCH_FACTOR)
			// {
			// _isTouched = true;
			// }
			// } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
			// // Check if it's on the ball
			// if (_isTouched)
			// {
			// // stop Pause mode if already enabled
			// togglePause(false);
			// if (wall.checkIfHit(_redBall.getCoordinates().getX(),
			// _redBall.getCoordinates().getY(),
			// _redBall.getGraphic().getWidth() / 2) == null)
			// {
			// _redBall.getCoordinates().setX(
			// (int) (event.getX() - _redBall.getGraphic().getWidth() / 2));
			// _redBall.getCoordinates().setY(
			// (int) (event.getY() - _redBall.getGraphic().getHeight() / 2));
			//
			// } else {
			// _isTouched = false;
			// }
			//
			// // Saving it's current position
			// if (_savePosition == 0)
			// {
			// _oldX = (int) (_redBall.getCoordinates().getX() +
			// _redBall.getGraphic().getWidth() / 2);
			// _oldY = (int) (_redBall.getCoordinates().getY() +
			// _redBall.getGraphic().getHeight() / 2);
			//
			// _savePosition = POSITION_TESTING_FACTOR;
			// } else
			// {
			// --_savePosition;
			// }
			// }
			// } else if (event.getAction() == MotionEvent.ACTION_UP)
			// {
			// // if (_onChangeGravity) {
			// // double gravityDegree = getGravityAngle();
			// //
			// // xVector = (float)(Math.cos(gravityDegree) * GRAVITY_FACTOR *
			// SLOW_MOTION_FACTOR);
			// // yVector = (float)(Math.sin(gravityDegree) * GRAVITY_FACTOR *
			// SLOW_MOTION_FACTOR);
			// // _onChangeGravity = false;
			// // }
			// if (_isTouched)
			// {
			// // Sets its speed and direction
			// _isTouched = false;
			//
			// _deltaX = (int) 2 * (event.getX() - _oldX) /
			// (POSITION_TESTING_FACTOR);
			// _deltaY = (int) 2 * (event.getY() - _oldY) /
			// (POSITION_TESTING_FACTOR);
			// }
			// }
			return true;
		}
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
	{
		// TODO Auto-generated method stub

	}

	public void surfaceCreated(SurfaceHolder holder)
	{
		if ((_thread == null) || (_thread.isAlive() == false))
		{
			_thread = new LifeCycleThread(getHolder(), this);
			_thread.setRunning(true);
			_thread.start();
		}
	}

	public void surfaceDestroyed(SurfaceHolder holder)
	{
		boolean retry = true;

		_thread.setRunning(false);
		while (retry)
		{
			try
			{
				_thread.join();
				retry = false;
			} catch (InterruptedException e)
			{
				// ?
			}
		}
	}

	class LifeCycleThread extends Thread
	{
		private SurfaceHolder _surfaceHolder;
		private Panel _panel;
		private boolean _run = false;
		private Canvas c;

		public LifeCycleThread(SurfaceHolder surfaceHolder, Panel panel)
		{
			_surfaceHolder = surfaceHolder;
			_panel = panel;
		}

		public SurfaceHolder getSurfaceHolder()
		{
			return _surfaceHolder;
		}

		public void setRunning(boolean run)
		{
			_run = run;
		}

		@Override
		public void run()
		{
			while (_run)
			{
				c = null;
				try
				{
					c = _surfaceHolder.lockCanvas(null);
					synchronized (_surfaceHolder)
					{
						_panel.updatePhysics();
						_panel.onDraw(c);
					}
				} finally
				{
					if (c != null)
					{
						_surfaceHolder.unlockCanvasAndPost(c);
					}
				}
			}

		}
		
		Canvas getCanvas() {
			return c;
		}

	}
}